Skip to content

Visualizer: a display of literals has no steps (P40) - #48

Merged
cedricvogel-leo merged 1 commit into
mainfrom
feature/literal-displays
Nov 4, 2026
Merged

cedricvogel-leo merged 1 commit into
mainfrom
feature/literal-displays

Conversation

@cedricvogel-leo

@cedricvogel-leo cedricvogel-leo commented Nov 4, 2026 •

Copy link
Copy Markdown
Collaborator

What

A list, tuple, set or dict display no longer has a step of its own: once its parts are values, it reads as its value, as on paper. This applies in Ersetzung and Kasten, since both show the same trace.

  • A display of literals has no steps, nested at any depth: baum = ["+", ["*", 2, ["-", 7, 3]], ["/", ["+", 1, 2], 3]] has one step, the assignment.

  • Negative number literals (-3, -2.5, -1j: unary minus applied to a number literal) have no step, inside a display or anywhere else. ["-", 7, -3] and [-1, 2] have no steps.

  • Names, calls and operators keep their steps, and the step that only built the display is gone:

    • [1 + 2, 3, 4] → [3, 3, 4]
    • [a, 2] → [5, 2]
    • [[1, 2], x] → [[1, 2], 7]
    • ["+", 1, ["*", n, 3]] → ["+", 1, ["*", 2, 3]]

    Each is one step.

  • The display keeps its step only where its value reads differently from what is written:

    • unpacking: [*b, 2] → [1, 2], {**d, "j": 2};
    • a set or dict that loses duplicates: {1, 1} → {1}.

    These are the only cases where the «build» step changes something.

  • Unchanged:

    • dauer[1] → 2;
    • notenschnitt(noten) → notenschnitt([5, 4.5, 6]);
    • the IndexError step for dauer[3].

    [1, 2, 30][1] → 2 is now a single step: the literal's step [1, 2, 30] → [1, 2, 30] changed nothing. The P39 check now expects that.

Fixed along the way (please confirm): unpacking in a display gave the wrong value. [*b, 2] with b = [1] gave [[1], 2]; Python gives [1, 2]. The same happened for tuples and sets. I fixed it because the handlers being rewritten here contained the bug, and without the build step the wrong value would have reached the variables panel unseen. A check compares the result with Python.

Checks

  • scripts/check-runtime-lists.py:
    • The baum literal, ["-", 7, -3], [-1, 2], a mixed tuple/dict/set of literals and -3 have no steps except the assignment, and their values are Python's.
    • The four examples above have one step each, plus (n, -n, {n: [n]}) and [len([1, 2]), 3].
    • The unpacking and duplicate cases keep their step, with Python's value.
    • The P39 cases are unchanged except [1, 2, 30][1], which is now one step.
  • scripts/check-console-browser.mjs steps through a program with these displays in both Kasten and Ersetzung. Every step must change the code or the variables, and the program has exactly 10 steps (7 assignments, 3 substitutions).
  • Locally, lint, test:runtime, test:protocol and test:console pass.

How it goes live

  • Courses: merging to main deploys the embed, so the courses get it straight away.
  • IDE: set tag v0.1.24 on the merge commit, and I'll open the IDE bump PR.
  • Macro: no change.

If P37 (#49) is merged too, one tag covers both.

Manual tests (desktop, and iPad with an external keyboard)

  1. Visualize baum = ["+", ["*", 2, ["-", 7, 3]], ["/", ["+", 1, 2], 3]] in Ersetzung, then in Kasten. There is 1 step, and baum appears in the variables.
  2. Visualize q = ["-", 7, -3] and r = [-1, 2]. There is one step per line.
  3. Visualize the following, stepping with → (keyboard) or the buttons. Each line shows one substitution, then the assignment, and every step changes something:
    x = [1 + 2, 3, 4]
    a = 5
    y = [a, 2]
    z = [[1, 2], a]
    n = 2
    w = ["+", 1, ["*", n, 3]]
  4. P39 is unchanged:
    • dauer = [1, 2, 30], x = dauer[1] goes dauer[1] → 2;
    • [1, 2, 30][1] is one step to 2;
    • dauer[3] ends at the IndexError step;
    • notenschnitt(noten) → notenschnitt([5, 4.5, 6]).
  5. Options → «Kopieren → Kette» for item 3: the chain has the lines shown, with no line repeated.

Follow-ups (not fixed)

  • -x with x = 7 still has a step that changes nothing. After x → 7 the line reads -7, and the step -7 → -7 follows. I left it out because skipping it whenever the text matches would leave -(a + b) showing -(3). To decide: drop the unary-minus step when its operand is a name.
  • +3 (unary plus) keeps its step +3 → 3, which does change the text. Say if it should count as a literal too.
  • CI, first run: test:console failed in the input() check from P36, which this PR doesn't touch, and passed on a rerun. The console's text included the entry's «Visualisieren» button label before the input lines (">>> repl()\nVisualisieren\n> 1 + 2…"). That check is timing-dependent; it should read the transcript without the buttons.

🤖 Generated with Claude Code

A list, tuple, set or dict display records no step of its own once its parts
are values; a negative number literal records none either. Only unpacking and
a set or dict losing duplicates keep the display's step. Unpacking in a
display now gives Python's value ([*a, 2] was [[1], 2]).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@cedricvogel-leo
cedricvogel-leo force-pushed the feature/literal-displays branch from ddba69c to 3e746a2 Compare November 4, 2026 23:39
@cedricvogel-leo
cedricvogel-leo merged commit d78944a into main Nov 4, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant